package com.uniflow.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.uniflow.common.Result;
import com.uniflow.common.ResultCode;
import com.uniflow.entity.ApiKey;
import com.uniflow.entity.User;
import com.uniflow.mapper.ApiKeyMapper;
import com.uniflow.mapper.UserMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * API密钥认证过滤器
 * 支持通过API密钥进行身份认证和权限验证
 * 
 * @author uniflow
 * @since 1.0.0
 */
@Component
public class ApiKeyAuthenticationFilter extends OncePerRequestFilter {
    
    private static final Logger logger = LoggerFactory.getLogger(ApiKeyAuthenticationFilter.class);
    
    private static final String API_KEY_HEADER = "X-API-Key";
    private static final String API_SECRET_HEADER = "X-API-Secret";
    private static final String ON_BEHALF_OF_USER_HEADER = "X-On-Behalf-Of-User";
    
    @Autowired
    private ApiKeyMapper apiKeyMapper;
    
    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, 
                                   FilterChain filterChain) throws ServletException, IOException {
        
        // 检查是否是API密钥认证请求
        String apiKey = request.getHeader(API_KEY_HEADER);
        String apiSecret = request.getHeader(API_SECRET_HEADER);
        
        if (!StringUtils.hasText(apiKey) || !StringUtils.hasText(apiSecret)) {
            // 不是API密钥认证，继续其他认证方式
            filterChain.doFilter(request, response);
            return;
        }
        
        try {
            // 验证API密钥
            ApiKey keyEntity = apiKeyMapper.selectByAccessKey(apiKey);
            if (keyEntity == null) {
                sendErrorResponse(response, ResultCode.UNAUTHORIZED, "无效的API密钥");
                return;
            }
            
            // 验证密钥是否过期
            if (keyEntity.isExpired()) {
                sendErrorResponse(response, ResultCode.TOKEN_EXPIRED, "API密钥已过期");
                return;
            }
            
            // 验证秘密密钥
            if (!keyEntity.getSecretKey().equals(apiSecret)) {
                sendErrorResponse(response, ResultCode.UNAUTHORIZED, "API密钥验证失败");
                return;
            }
            
            // 检查应用状态
            if (keyEntity.getApplication() != null && !keyEntity.getApplication().isEnabled()) {
                sendErrorResponse(response, ResultCode.FORBIDDEN, "应用已被禁用");
                return;
            }
            
            // 检查IP白名单
            if (!isIpAllowed(request, keyEntity)) {
                sendErrorResponse(response, ResultCode.FORBIDDEN, "IP地址不在白名单中");
                return;
            }
            
            // 处理代理用户
            String onBehalfOfUser = request.getHeader(ON_BEHALF_OF_USER_HEADER);
            User targetUser = null;
            
            if (StringUtils.hasText(onBehalfOfUser)) {
                // 检查是否有代理权限
                if (!keyEntity.hasPermission("user:proxy")) {
                    sendErrorResponse(response, ResultCode.FORBIDDEN, "没有用户代理权限");
                    return;
                }
                
                // 查找目标用户
                targetUser = userMapper.selectByUsername(onBehalfOfUser);
                if (targetUser == null) {
                    targetUser = userMapper.selectById(onBehalfOfUser);
                }
                
                if (targetUser == null) {
                    sendErrorResponse(response, ResultCode.USER_NOT_FOUND, "代理用户不存在");
                    return;
                }
                
                if (targetUser.getStatus() != 1) {
                    sendErrorResponse(response, ResultCode.FORBIDDEN, "代理用户已被禁用");
                    return;
                }
            }
            
            // 创建认证对象
            ApiKeyAuthenticationToken authentication = createAuthentication(keyEntity, targetUser);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            
            // 记录API调用日志（异步）
            logApiCall(request, keyEntity, targetUser);
            
            // 继续过滤链
            filterChain.doFilter(request, response);
            
        } catch (Exception e) {
            logger.error("API密钥认证失败", e);
            sendErrorResponse(response, ResultCode.ERROR, "认证过程中发生错误");
        }
    }
    
    /**
     * 检查IP是否在白名单中
     */
    private boolean isIpAllowed(HttpServletRequest request, ApiKey apiKey) {
        if (apiKey.getApplication() == null) {
            return true;
        }
        
        String clientIp = getClientIpAddress(request);
        return apiKey.getApplication().isIpAllowed(clientIp);
    }
    
    /**
     * 获取客户端IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (StringUtils.hasText(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }
        
        String xRealIp = request.getHeader("X-Real-IP");
        if (StringUtils.hasText(xRealIp)) {
            return xRealIp;
        }
        
        return request.getRemoteAddr();
    }
    
    /**
     * 创建认证对象
     */
    private ApiKeyAuthenticationToken createAuthentication(ApiKey apiKey, User targetUser) {
        // 解析权限
        List<SimpleGrantedAuthority> authorities = parsePermissions(apiKey.getPermissions());
        
        // 创建主体信息
        ApiKeyPrincipal principal = new ApiKeyPrincipal(
                apiKey.getAccessKey(),
                apiKey.getAppId(),
                targetUser != null ? targetUser.getId() : null,
                targetUser != null ? targetUser.getUsername() : null
        );
        
        return new ApiKeyAuthenticationToken(principal, apiKey.getSecretKey(), authorities);
    }
    
    /**
     * 解析权限字符串
     */
    private List<SimpleGrantedAuthority> parsePermissions(String permissions) {
        if (!StringUtils.hasText(permissions)) {
            return Collections.emptyList();
        }
        
        return Arrays.stream(permissions.split(","))
                .map(String::trim)
                .filter(StringUtils::hasText)
                .map(SimpleGrantedAuthority::new)
                .collect(java.util.stream.Collectors.toList());
    }
    
    /**
     * 记录API调用日志
     */
    private void logApiCall(HttpServletRequest request, ApiKey apiKey, User targetUser) {
        // 这里可以异步记录API调用日志到数据库
        // 包括：应用ID、API路径、请求方法、IP地址、用户代理、代理用户等信息
        logger.info("API调用: appId={}, accessKey={}, path={}, method={}, ip={}, onBehalfOf={}",
                apiKey.getAppId(),
                apiKey.getAccessKey(),
                request.getRequestURI(),
                request.getMethod(),
                getClientIpAddress(request),
                targetUser != null ? targetUser.getUsername() : null
        );
    }
    
    /**
     * 发送错误响应
     */
    private void sendErrorResponse(HttpServletResponse response, ResultCode resultCode, String message) 
            throws IOException {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/json;charset=UTF-8");
        
        Result<Object> result = Result.error(resultCode, message);
        String jsonResponse = objectMapper.writeValueAsString(result);
        
        response.getWriter().write(jsonResponse);
        response.getWriter().flush();
    }
    
    /**
     * API密钥主体信息
     */
    public static class ApiKeyPrincipal {
        private final String accessKey;
        private final String appId;
        private final String userId;
        private final String username;
        
        public ApiKeyPrincipal(String accessKey, String appId, String userId, String username) {
            this.accessKey = accessKey;
            this.appId = appId;
            this.userId = userId;
            this.username = username;
        }
        
        public String getAccessKey() {
            return accessKey;
        }
        
        public String getAppId() {
            return appId;
        }
        
        public String getUserId() {
            return userId;
        }
        
        public String getUsername() {
            return username;
        }
        
        @Override
        public String toString() {
            return "ApiKeyPrincipal{" +
                    "accessKey='" + accessKey + '\'' +
                    ", appId='" + appId + '\'' +
                    ", userId='" + userId + '\'' +
                    ", username='" + username + '\'' +
                    '}';
        }
    }
    
    /**
     * API密钥认证令牌
     */
    public static class ApiKeyAuthenticationToken extends UsernamePasswordAuthenticationToken {
        
        public ApiKeyAuthenticationToken(Object principal, Object credentials, 
                                        List<SimpleGrantedAuthority> authorities) {
            super(principal, credentials, authorities);
        }
        
        @Override
        public boolean isAuthenticated() {
            return true;
        }
    }
}